package org.hilo.boot.core.logback;

import ch.qos.logback.classic.LoggerContext;
import org.slf4j.ILoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.logback.LogbackLoggingSystem;
import org.springframework.util.Assert;

import java.security.CodeSource;
import java.security.ProtectionDomain;

/**
 * 重载springboot的LogbackLoggingSystem
 * （springboot默认的LogbackLoggingSystem会生成一个过滤掉所有日志的TurboFilter
 * ，导致在spring加载日志前的所有日志会丢失）
 * 
 * 使用FixedLogbackLoggingSystem配合logback默认配置logback.xml可以打印出spring加载日志前的所有日志
 * 
 * @author zollty
 * @since 2019年1月3日
 */
public class FixedLogbackLoggingSystem extends LogbackLoggingSystem {

    /**
     * @param classLoader
     */
    public FixedLogbackLoggingSystem(ClassLoader classLoader) {
        super(classLoader);
    }
    
    @Override
    public void beforeInitialize() {
        LoggerContext loggerContext = getLoggerContext();
        super.beforeInitialize();
        loggerContext.getTurboFilterList().clear();
    }
    
    private LoggerContext getLoggerContext() {
        ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
        Assert.isInstanceOf(LoggerContext.class, factory,
                String.format(
                        "LoggerFactory is not a Logback LoggerContext but Logback is on "
                                + "the classpath. Either remove Logback or the competing "
                                + "implementation (%s loaded from %s). If you are using "
                                + "WebLogic you will need to add 'org.slf4j' to "
                                + "prefer-application-packages in WEB-INF/weblogic.xml",
                        factory.getClass(), getLocation(factory)));
        return (LoggerContext) factory;
    }
    
    private Object getLocation(ILoggerFactory factory) {
        try {
            ProtectionDomain protectionDomain = factory.getClass().getProtectionDomain();
            CodeSource codeSource = protectionDomain.getCodeSource();
            if (codeSource != null) {
                return codeSource.getLocation();
            }
        }
        catch (SecurityException ex) {
            // Unable to determine location
        }
        return "unknown location";
    }

}
